#!/usr/bin/env python
# encoding: utf-8
import json
import pandas as pd
from utils.time_utisl import *
from utils.common import *
from feature_set.base_feature import BaseFeature, RequstData


class CrossUnBaseV1(BaseFeature):
    def __init__(self):
        super().__init__()
        self.apply_time = None
        self.country_abbr = None
        self.sms_data_df = None
        self.calllog_data_df = None
        self.applist_data_df = None
        self.sos_data_df = None
        self.function_map = {
            'gen_cross_feature': self.gen_cross_feature
        }

    def load_conf(self):
        """
        load config file
        Returns:

        """
        pass

    def load_request(self, request_data: RequstData):
        """
        get request data and format feature input data
        Args:
            request_data: input detail data

        Returns:
            format sms_data calllog_data applist_data sos_data
        """
        self.apply_time = datetime.strptime(str(request_data.apply_time), "%Y-%m-%d %H:%M:%S")
        self.country_abbr = request_data.country_abbr
        sms_data = request_data.data_sources.get('sms_data', [])
        calllog_data = request_data.data_sources.get('calllog_data', [])
        applist_data = request_data.data_sources.get('applist_data', [])
        sos_data = request_data.data_sources.get('contact_list', [])

        if sms_data:
            self.sms_data_df = pd.DataFrame(sms_data)
        else:
            self.sms_data_df = pd.DataFrame(columns=['body', 'phone', 'read', 'src_phone', 'time', 'type', 'day_interval'])
            self.logger.info('输入数据sms_data结点为空')

        if calllog_data:
            self.calllog_data_df = pd.DataFrame(calllog_data)
        else:
            self.calllog_data_df = pd.DataFrame(columns=['call_log_address_name', 'call_log_attribution', 'call_log_connection_status', 'call_log_duration', 'call_log_number', 'calloranswer_time', 'day_interval'])
            self.logger.info('输入数据calllog_data结点为空')

        if applist_data:
            self.applist_data_df = pd.DataFrame(applist_data)
        else:
            self.applist_data_df = pd.DataFrame(columns=['app_name', 'app_package', 'app_version', 'device_id', 'fi_time', 'isSystem', 'lu_time', 'day_interval'])
            self.logger.info('输入数据applist_data结点为空')

        if sos_data:
            self.sos_data_df = pd.DataFrame(sos_data)
        else:
            self.sos_data_df = pd.DataFrame(columns=['appUserId', 'contactName', 'contactPhoneNumber', 'contactRelationship', 'idNumber', 'phoneNumber'])
            self.logger.info('输入数据sos_data结点为空')

        self.process_data()

    def process_app_name(self, app_name):
        app_name = app_name.lower()
        app_name = sp_string_replace(app_name)
        app_name = app_name.replace('\xa0', ' ')
        app_name = app_name.replace('\'s', '')
        return app_name

    def process_data(self):
        if not self.sms_data_df.empty:
            self.sms_data_df['time'] = self.sms_data_df['time'].apply(time_trans, args=(self.country_abbr,))
            self.sms_data_df = self.sms_data_df[self.sms_data_df['time'] < self.apply_time]
            self.sms_data_df['day_interval'] = (pd.to_datetime(self.apply_time) - pd.to_datetime(self.sms_data_df['time'])).dt.total_seconds() / (60 * 60 * 24)
            self.sms_data_df = self.sms_data_df.astype({'body': str, 'read': str, 'src_phone': str, 'phone': str})
            if not self.sms_data_df.empty:
                self.sms_data_df['src_phone'] = self.sms_data_df.apply(lambda x: x['phone'] if len(x['src_phone']) < len(x['phone']) else x['src_phone'], axis=1)
                self.sms_data_df['src_phone'] = self.sms_data_df['src_phone'].apply(phone_normalize, args=(self.country_abbr,))
            self.sms_data_df['body'] = self.sms_data_df['body'].str.lower()

        if not self.calllog_data_df.empty:
            self.calllog_data_df['calloranswer_time'] = self.calllog_data_df['calloranswer_time'].apply(time_trans, args=(self.country_abbr,))
            self.calllog_data_df = self.calllog_data_df[self.calllog_data_df['calloranswer_time'] < self.apply_time]
            self.calllog_data_df['day_interval'] = (pd.to_datetime(self.apply_time) - pd.to_datetime(self.calllog_data_df['calloranswer_time'])).dt.total_seconds() / (60 * 60 * 24)
            self.calllog_data_df['call_log_connection_status'] = self.calllog_data_df['call_log_connection_status'].astype(str)
            self.calllog_data_df['call_log_number'] = self.calllog_data_df['call_log_number'].apply(phone_normalize, args=(self.country_abbr,))

        if not self.applist_data_df.empty:
            self.applist_data_df = self.applist_data_df[self.applist_data_df['isSystem'] == 0]
            self.applist_data_df['lu_time'] = self.applist_data_df['lu_time'].apply(time_trans, args=(self.country_abbr,))
            self.applist_data_df = self.applist_data_df[self.applist_data_df['lu_time'] < self.apply_time]
            self.applist_data_df['day_interval'] = (pd.to_datetime(self.apply_time) - pd.to_datetime(self.applist_data_df['lu_time'])).dt.total_seconds() / (60 * 60 * 24)
            self.applist_data_df['app_name'] = self.applist_data_df['app_name'].apply(self.process_app_name)

        if not self.sos_data_df.empty:
            self.sos_data_df['contactPhoneNumber'] = self.sos_data_df['contactPhoneNumber'].apply(phone_normalize, args=(self.country_abbr,))

    def gen_cross_feature(self):
        feature_dict = {}
        sms_call_cross_feature_dict = self.__gen_sms_call_cross_feature(self.sms_data_df, self.calllog_data_df)
        sms_app_cross_feature_dict = self.__gen_sms_app_cross_feature(self.sms_data_df, self.applist_data_df)
        sms_sos_cross_feature_dict = self.__gen_sms_sos_cross_feature(self.sms_data_df, self.sos_data_df)
        call_sos_cross_feature_dict = self.__gen_call_sos_cross_feature(self.calllog_data_df, self.sos_data_df)
        feature_dict.update(sms_call_cross_feature_dict)
        feature_dict.update(sms_app_cross_feature_dict)
        feature_dict.update(sms_sos_cross_feature_dict)
        feature_dict.update(call_sos_cross_feature_dict)

        for key, value in feature_dict.items():
            feature_dict[key] = value if not np.isnan(value) else -999
        return feature_dict

    def __gen_sms_call_cross_feature(self, sms_data_df, calllog_data_df):
        feature_dict = {}
        day_list = [1, 3, 7, 15, 30, 60, 90, 180, 360]
        read_list = ['0', '1', 'all']
        status_list = ['outgoing_call', 'incoming_call', 'missed_call', 'cancellation_call', 'all']

        for day in day_list:
            tmp1_sms_data_df = sms_data_df[sms_data_df['day_interval'] <= day]
            tmp1_calllog_data_df = calllog_data_df[calllog_data_df['day_interval'] <= day]
            for read in read_list:
                if read == 'all':
                    tmp2_sms_data_df = tmp1_sms_data_df
                else:
                    tmp2_sms_data_df = tmp1_sms_data_df[tmp1_sms_data_df['read'] == read]
                for status in status_list:
                    if status == 'all':
                        tmp2_calllog_data_df = tmp1_calllog_data_df
                    else:
                        tmp2_calllog_data_df = tmp1_calllog_data_df[
                            tmp1_calllog_data_df['call_log_connection_status'] == status]
                    sms_phone_set = set(tmp2_sms_data_df['src_phone'].unique())
                    call_phone_set = set(tmp2_calllog_data_df['call_log_number'].unique())
                    union_set = sms_phone_set | call_phone_set
                    inter_set = sms_phone_set & call_phone_set
                    diff1_set = sms_phone_set - call_phone_set
                    diff2_set = call_phone_set - sms_phone_set
                    sms_phone_num = len(sms_phone_set)
                    call_phone_num = len(call_phone_set)
                    sms_call_union_phone_num = len(union_set)
                    sms_call_inter_phone_num = len(inter_set)
                    sms_call_diff1_phone_num = len(diff1_set)
                    call_sms_diff2_phone_num = len(diff2_set)
                    sms_union_phone_num_ratio = divide(sms_phone_num, sms_call_union_phone_num)
                    call_union_phone_num_ratio = divide(call_phone_num, sms_call_union_phone_num)
                    inter_sms_phone_num_ratio = divide(sms_call_inter_phone_num, sms_phone_num)
                    inter_call_phone_num_ratio = divide(sms_call_inter_phone_num, call_phone_num)
                    sms_call_diff1_phone_num_ratio = divide(sms_call_diff1_phone_num, sms_phone_num)
                    call_sms_diff2_phone_num_ratio = divide(call_sms_diff2_phone_num, call_phone_num)
                    suffix = f'd{day}_read{read}_{status}'
                    feature_dict[f'sms_call_union_phone_num_{suffix}'] = sms_call_union_phone_num
                    feature_dict[f'sms_call_inter_phone_num_{suffix}'] = sms_call_inter_phone_num
                    feature_dict[f'sms_call_diff1_phone_num_{suffix}'] = sms_call_diff1_phone_num
                    feature_dict[f'call_sms_diff2_phone_num_{suffix}'] = call_sms_diff2_phone_num
                    feature_dict[f'sms_union_phone_num_ratio_{suffix}'] = sms_union_phone_num_ratio
                    feature_dict[f'call_union_phone_num_ratio_{suffix}'] = call_union_phone_num_ratio
                    feature_dict[f'inter_sms_phone_num_ratio_{suffix}'] = inter_sms_phone_num_ratio
                    feature_dict[f'inter_call_phone_num_ratio_{suffix}'] = inter_call_phone_num_ratio
                    feature_dict[f'sms_call_diff1_phone_num_ratio_{suffix}'] = sms_call_diff1_phone_num_ratio
                    feature_dict[f'call_sms_diff2_phone_num_ratio_{suffix}'] = call_sms_diff2_phone_num_ratio
        return feature_dict

    def __gen_sms_app_cross_feature(self, sms_data_df, applist_data_df):
        feature_dict = {}
        day_list = [1, 3, 7, 15, 30, 60, 90, 180, 360]
        for day in day_list:
            tmp1_sms_data_df = sms_data_df[sms_data_df['day_interval'] <= day]
            tmp1_applist_data_df = applist_data_df[applist_data_df['day_interval'] <= day]
            sms_body_list = tmp1_sms_data_df['body'].tolist()
            app_name_list = tmp1_applist_data_df['app_name'].tolist()
            app_name_num_dict = {}
            for app in app_name_list:
                for body in sms_body_list:
                    if app in body:
                        app_name_num_dict[app] = app_name_num_dict.get(app, 0) + 1
            app_name_num_dict_values = app_name_num_dict.values()
            app_in_sms_diff_num = len(app_name_num_dict_values)
            app_in_sms_sum = sum(app_name_num_dict_values)
            app_in_sms_max_num = max(app_name_num_dict_values) if app_in_sms_diff_num != 0 else 0
            app_in_sms_min_num = min(app_name_num_dict_values) if app_in_sms_diff_num != 0 else 0
            app_in_sms_diff_num_ratio = divide(app_in_sms_diff_num, len(sms_body_list))
            app_in_sms_sum_ratio = divide(app_in_sms_sum, len(sms_body_list))
            app_in_sms_max_num_ratio = divide(app_in_sms_max_num, len(sms_body_list))
            app_in_sms_min_num_ratio = divide(app_in_sms_min_num, len(sms_body_list))

            app_name_split_num_dict = {}
            for app in app_name_list:
                app_split_list = app.split(' ')
                for app_split in app_split_list:
                    if app_split.isdigit():
                        continue
                    for body in sms_body_list:
                        if app_split in body:
                            app_name_split_num_dict[app_split] = app_name_split_num_dict.get(app_split, 0) + 1
            app_name_split_num_dict_values = app_name_split_num_dict.values()
            app_split_in_sms_diff_num = len(app_name_split_num_dict_values)
            app_split_in_sms_sum = sum(app_name_split_num_dict_values)
            app_split_in_sms_max_num = max(app_name_split_num_dict_values) if app_split_in_sms_diff_num != 0 else 0
            app_split_in_sms_min_num = min(app_name_split_num_dict_values) if app_split_in_sms_diff_num != 0 else 0
            app_split_in_sms_diff_num_ratio = divide(app_split_in_sms_diff_num, len(sms_body_list))
            app_split_in_sms_sum_ratio = divide(app_split_in_sms_sum, len(sms_body_list))
            app_split_in_sms_max_num_ratio = divide(app_split_in_sms_max_num, len(sms_body_list))
            app_split_in_sms_min_num_ratio = divide(app_split_in_sms_min_num, len(sms_body_list))

            suffix = f'd{day}'
            feature_dict[f'app_in_sms_diff_num_{suffix}'] = app_in_sms_diff_num
            feature_dict[f'app_in_sms_sum_{suffix}'] = app_in_sms_sum
            feature_dict[f'app_in_sms_max_num_{suffix}'] = app_in_sms_max_num
            feature_dict[f'app_in_sms_min_num_{suffix}'] = app_in_sms_min_num
            feature_dict[f'app_in_sms_diff_num_ratio_{suffix}'] = app_in_sms_diff_num_ratio
            feature_dict[f'app_in_sms_sum_ratio_{suffix}'] = app_in_sms_sum_ratio
            feature_dict[f'app_in_sms_max_num_ratio_{suffix}'] = app_in_sms_max_num_ratio
            feature_dict[f'app_in_sms_min_num_ratio_{suffix}'] = app_in_sms_min_num_ratio
            feature_dict[f'app_split_in_sms_diff_num_{suffix}'] = app_split_in_sms_diff_num
            feature_dict[f'app_split_in_sms_sum_{suffix}'] = app_split_in_sms_sum
            feature_dict[f'app_split_in_sms_max_num_{suffix}'] = app_split_in_sms_max_num
            feature_dict[f'app_split_in_sms_min_num_{suffix}'] = app_split_in_sms_min_num
            feature_dict[f'app_split_in_sms_diff_num_ratio_{suffix}'] = app_split_in_sms_diff_num_ratio
            feature_dict[f'app_split_in_sms_sum_ratio_{suffix}'] = app_split_in_sms_sum_ratio
            feature_dict[f'app_split_in_sms_max_num_ratio_{suffix}'] = app_split_in_sms_max_num_ratio
            feature_dict[f'app_split_in_sms_min_num_ratio_{suffix}'] = app_split_in_sms_min_num_ratio
        return feature_dict

    def __gen_sms_sos_cross_feature(self, sms_data_df, sos_data_df):
        feature_dict = {}
        day_list = [1, 3, 7, 15, 30, 60, 90, 180, 360]
        for day in day_list:
            tmp1_sms_data_df = sms_data_df[sms_data_df['day_interval'] <= day]

            sms_phone_list = tmp1_sms_data_df['src_phone'].tolist()
            contact_phone_list = sos_data_df['contactPhoneNumber'].unique().tolist()

            contact_phone_num_dict = {}
            for cphone in contact_phone_list:
                num = len([p for p in sms_phone_list if p == cphone])
                contact_phone_num_dict[cphone] = contact_phone_num_dict.get(cphone, 0) + num
            contact_phone_num_dict_values = contact_phone_num_dict.values()
            sos_in_sms_sum = sum(contact_phone_num_dict_values)
            sos_in_sms_sum_ratio = divide(sos_in_sms_sum, len(sms_phone_list))

            suffix = f'd{day}'
            feature_dict[f'sos_in_sms_sum_{suffix}'] = sos_in_sms_sum
            feature_dict[f'sos_in_sms_sum_ratio_{suffix}'] = sos_in_sms_sum_ratio
        return feature_dict

    def __gen_call_sos_cross_feature(self, calllog_data_df, sos_data_df):
        feature_dict = {}
        day_list = [1, 3, 7, 15, 30, 60, 90, 180, 360]
        for day in day_list:
            tmp1_calllog_data_df = calllog_data_df[calllog_data_df['day_interval'] <= day]

            call_phone_list = tmp1_calllog_data_df['call_log_number'].tolist()
            contact_phone_list = sos_data_df['contactPhoneNumber'].unique().tolist()

            contact_phone_num_dict = {}
            for cphone in contact_phone_list:
                num = len([p for p in call_phone_list if p == cphone])
                contact_phone_num_dict[cphone] = contact_phone_num_dict.get(cphone, 0) + num
            contact_phone_num_dict_values = contact_phone_num_dict.values()
            sos_in_call_sum = sum(contact_phone_num_dict_values)
            sos_in_call_sum_ratio = divide(sos_in_call_sum, len(call_phone_list))

            suffix = f'd{day}'
            feature_dict[f'sos_in_call_sum_{suffix}'] = sos_in_call_sum
            feature_dict[f'sos_in_call_sum_ratio_{suffix}'] = sos_in_call_sum_ratio
        return feature_dict
